package cn.iphone.NPlayer.service.impl;

import cn.iphone.NPlayer.constants.RedisSmsConstants;
import cn.iphone.NPlayer.domain.Login;
import cn.iphone.NPlayer.domain.User;
import cn.iphone.NPlayer.domain.UserAccount;
import cn.iphone.NPlayer.domain.UserBaseInfo;
import cn.iphone.NPlayer.dto.PhoneRegisterDto;
import cn.iphone.NPlayer.dto.RedisSmsDto;
import cn.iphone.NPlayer.exception.GlobalExceptionCodeEnum;
import cn.iphone.NPlayer.fegin.LoginService;
import cn.iphone.NPlayer.mapper.UserMapper;
import cn.iphone.NPlayer.result.JSONResult;
import cn.iphone.NPlayer.service.IUserAccountService;
import cn.iphone.NPlayer.service.IUserBaseInfoService;
import cn.iphone.NPlayer.service.IUserService;
import cn.iphone.NPlayer.util.AssertUtil;
import cn.iphone.NPlayer.util.BitStatesUtils;
import cn.iphone.NPlayer.util.StrUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author ikun
 * @since 2022-11-17
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private LoginService loginService;
    @Autowired
    private IUserBaseInfoService userBaseInfoService;
    @Autowired
    private IUserAccountService userAccountService;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(PhoneRegisterDto phoneRegisterDto) {
        String mobile = phoneRegisterDto.getMobile();
        String password = phoneRegisterDto.getPassword();
        Integer regChannel = phoneRegisterDto.getRegChannel();
        String smsCode = phoneRegisterDto.getSmsCode();
        // 1.参数校验JSR303
        // 2.判断手机号是否注册
        Wrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("phone", mobile);
        User user = selectOne(wrapper);
        AssertUtil.isNull(user, GlobalExceptionCodeEnum.USER_PHONE_EXISTS_ERROR);
        // 3.判断手机验证码是否过期&正确
        String redisKey = String.format(RedisSmsConstants.REDIS_REGISTER_PHONE_KEY, mobile);
        Object obj = redisTemplate.opsForValue().get(redisKey);
        AssertUtil.isNotNull(obj , GlobalExceptionCodeEnum.USER_SMS_CODE_EXPIRED_ERROR);
        RedisSmsDto redisSmsDto = (RedisSmsDto)obj;
        AssertUtil.isEquals(redisSmsDto.getCode(), smsCode, GlobalExceptionCodeEnum.USER_SMS_CODE_ERROR);

        // 4.调用uaa服务，保存login信息，并接收主键
        JSONResult jsonResult = saveLogin(mobile, password);
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalExceptionCodeEnum.USER_REGISTER_ERROR);
        // 防御性编程
        Long loginId = Long.valueOf(jsonResult.getData().toString());
        AssertUtil.isNotNull(jsonResult.getData(), GlobalExceptionCodeEnum.USER_REGISTER_ERROR);

        // 5.保存user信息
        Long userId = saveUser(loginId, mobile);
        // 6.初始化account
        initUserAccount(userId);

        // 7.初始化baseinfo
        initUserBaseInfo(userId, regChannel);

    }

    /**
     * 初始化userbaseinfo信息
     * @param userId
     * @param regChannel
     */
    private void initUserBaseInfo(Long userId, Integer regChannel) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfo.setId(userId);
        userBaseInfo.setRegChannel(regChannel);
        userBaseInfoService.insert(userBaseInfo);
    }

    /**
     * 初始化账户信息
     * @param userId
     */
    private void initUserAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setId(userId);
        userAccount.setCreateTime(new Date().getTime());
        userAccount.setPassword(StrUtils.getRandomString(6));
        userAccountService.insert(userAccount);
    }

    /**
     * 保存user信息
     * @param loginId
     */
    private Long saveUser(Long loginId, String phone) {
        User user = new User();
        user.setCreateTime(new Date().getTime());
        user.setPhone(phone);
        user.setNickName(phone);
        user.setLoginId(loginId);
        long state = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);
        state = BitStatesUtils.addState(state, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(state);
        insert(user);
        return user.getId();
    }

    /**
     * 保存login信息
     * @param mobile
     * @param password
     * @return
     */
    private JSONResult saveLogin(String mobile, String password) {
        Login login = new Login();
        login.setUsername(mobile);
        login.setPassword(password);
        login.setType(Login.TYPE_HOME);
        login.setEnabled(true);
        return loginService.saveOrUpdate(login);

    }
}
